package com.jacob.androidframe.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Locale;
import java.util.Map;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import com.jacob.androidframe.controls.ApplicationExtend;

public class UtilNet
{
	public static final String	DEFAULT_CHARSET		= "UTF-8";
	public static final int		DEFAULT_TIME_OUT	= 10 * 1000;
	
	private static final String USER_AGENT = getUserAgent();

	public static String getUrlWithParam(String pUrl, Map<String, Object> pUrlParamMap, String pCharset)
	{
		if (TextUtils.isEmpty(pUrl)) {
			return "";
		}

		StringBuilder _StringBuilder = new StringBuilder();
		_StringBuilder.append(pUrl.trim());

		if (pUrlParamMap == null) {
			return _StringBuilder.toString();
		}

		_StringBuilder.append("?");
		for (String _Key : pUrlParamMap.keySet()) {
			if (!TextUtils.isEmpty(_Key)) {
				Object _Value = pUrlParamMap.get(_Key);
				_StringBuilder.append(encode(_Key, pCharset))
						.append("=")
						.append(encode(_Value, pCharset))
						.append("&");
			}
		}

		if (_StringBuilder.lastIndexOf("&") == _StringBuilder.length() - 1 || _StringBuilder.lastIndexOf("?") == _StringBuilder.length() - 1) {
			_StringBuilder.deleteCharAt(_StringBuilder.length() - 1);
		}

		return _StringBuilder.toString();
	}

	public static HttpURLConnection getConnection(String pUrl, Map<String, Object> pUrlParamMap, Map<String, String> pRequestPropertyMap, String pCharset, Integer pTimeOut) throws IOException
	{
		String _UrlWithParam = getUrlWithParam(pUrl, pUrlParamMap, pCharset);

		URL _URL;
		try {
			_URL = new URL(_UrlWithParam);
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}

		HttpURLConnection _HttpURLConnection = (HttpURLConnection) _URL.openConnection();

		if (pTimeOut != null) {
			_HttpURLConnection.setConnectTimeout(pTimeOut);
			_HttpURLConnection.setReadTimeout(pTimeOut);
		} else {
			_HttpURLConnection.setConnectTimeout(DEFAULT_TIME_OUT);
			_HttpURLConnection.setReadTimeout(DEFAULT_TIME_OUT);
		}

		setRequestProperty(_HttpURLConnection, pRequestPropertyMap, pCharset);

		return _HttpURLConnection;
	}

	public static void setRequestProperty(HttpURLConnection pHttpURLConnection, Map<String, String> pRequestPropertyMap, String pCharset)
	{
		if (pHttpURLConnection == null || pRequestPropertyMap == null || pRequestPropertyMap.size() <= 0) {
			return;
		}

		for (String _Key : pRequestPropertyMap.keySet()) {
			if (!TextUtils.isEmpty(_Key)) {
				String _Value = pRequestPropertyMap.get(_Key);
				pHttpURLConnection.setRequestProperty(_Key, _Value);
			}
		}

		// 表明用户所使用的浏览器标识，主要用于统计的目的。
		 pHttpURLConnection.setRequestProperty("User-Agent", USER_AGENT);

		// 表明客户同端可接受的请求回应的媒体类型范围列表。星号“*”用于按范围将类型分组，用“*/*”指示可接受全部类型；用“type/*”指示可接受 type类型的所有子类型，如“ Accept: image/gif, image/jpeg, */*”。
		// pHttpURLConnection.setRequestProperty("Accept", "text/*");

		// 客户端所能识别的语言，格式：“Accept-Language: 语言1[:权重]，语言2[:权重]”，如：” Accept-Language: zh, en;q=0.7”。
		// pHttpURLConnection.setRequestProperty("Accept-Language", "zh, en;q=0.7");

		// 客户端所能识别的字符集编码格式，格式：“Accept-Charset: 字符集1[:权重]，字符集2[:权重]”，如：“ Accept-Charset: iso-8859-5, unicode-1-1;q=0.8”。
		if (TextUtils.isEmpty(pCharset)) {
			pHttpURLConnection.setRequestProperty("Accept-Charset", DEFAULT_CHARSET);
		} else {
			pHttpURLConnection.setRequestProperty("Accept-Charset", pCharset);
		}

		// 客户端所能识别的编码压缩格式，如：“Accept-Encoding: gzip, deflate”；
		// pHttpURLConnection.setRequestProperty("Accept-Encoding", "gzip, deflate");

		// 客户端发送的数据体的内容类型，如：“Content-Type: application/x-www-form-urlencoded”为以普通的POST方法发送的数据；“Content-Type: multipart/form-data; boundary=---------------------------5169208281820”，则表明数据体由多部分组成，分隔符为
		// “-----------------------------5169208281820”；
		// if (TextUtils.isEmpty(pCharset)) {
		// pHttpURLConnection.setRequestProperty("Content-Type", "text/plain; charset=" + DEFAULT_CHARSET);
		// } else {
		// pHttpURLConnection.setRequestProperty("Content-Type", "text/plain; charset=" + pCharset);
		// }
		// pHttpURLConnection.setRequestProperty("Content-type", "application/x-java-serialized-object");
		// pHttpURLConnection.setRequestProperty("Content-type", "application/x-www-form-urlencoded");

		// 客户端所能识别的编码压缩格式，如：“Content-Encoding: gzip, deflate”；
		// pHttpURLConnection.setRequestProperty("Content-Encoding", "gzip, deflate");

		// 客户端以POST方法上传数据时数据体部分的内容长度，如：“ Content-Length: 24”；
		// pHttpURLConnection.setRequestProperty("Content-Length", "25163");

		// pHttpURLConnection.setRequestProperty("http.keepAlive", "false");

	}

	public static void setRequestBodyParam(HttpURLConnection pHttpURLConnection, Map<String, Object> pBodyParamMap, String pCharset) throws IOException
	{
		if (pHttpURLConnection == null) {
			return;
		}

		if (pBodyParamMap == null || pBodyParamMap.size() <= 0) {
			pHttpURLConnection.setRequestMethod(HttpType.GET.getName());
			pHttpURLConnection.setDoOutput(false);
		} else {
			pHttpURLConnection.setRequestMethod(HttpType.POST.getName());
			pHttpURLConnection.setDoOutput(true);
		}

		if (pHttpURLConnection.getDoOutput()) {
			StringBuilder _StringBuilder = new StringBuilder();

			for (String _Key : pBodyParamMap.keySet()) {
				if (!TextUtils.isEmpty(_Key)) {
					Object _Value = pBodyParamMap.get(_Key);
					_StringBuilder.append(encode(_Key, pCharset))
							.append("=")
							.append(encode(_Value, pCharset))
							.append("&");
				}
			}

			if (_StringBuilder.lastIndexOf("&") == _StringBuilder.length() - 1) {
				_StringBuilder.deleteCharAt(_StringBuilder.length() - 1);
			}

			OutputStream _OutputStream = null;

			try {
				_OutputStream = pHttpURLConnection.getOutputStream();
				UtilStream.writeBytesArrayToStream(_OutputStream, _StringBuilder.toString().getBytes());
			} finally {
				if (_OutputStream != null) {
					_OutputStream.close();
				}
			}
		}
	}

	public static String getStringResultFromURL(HttpURLConnection pHttpURLConnection, String pCharset) throws IOException
	{
		if (pHttpURLConnection == null) {
			return null;
		}

		int _Code = -1;
		InputStream _InputStream = null;
		String _Result = "";

		try {
			_Code = pHttpURLConnection.getResponseCode();
			_InputStream = pHttpURLConnection.getInputStream();
			_Result = UtilStream.readStreamAsString(_InputStream, pCharset);
		} finally {
			if (_InputStream != null) {
				_InputStream.close();
			}
			try {
				Log.i("UtilNet", pCharset);
			} catch (NullPointerException e) {
			}
			Log.i("UtilNet", _Code + "");
			try {
				Log.i("UtilNet", _Result);
			} catch (NullPointerException e) {
			}
		}

		return _Result;
	}

	public static String getStringResultFromURL(String pUrl, Map<String, Object> pUrlParamMap, Map<String, String> pRequestPropertyMap, String pCharset, Integer pTimeOut, Map<String, Object> pBodyParamMap) throws IOException
	{
		HttpURLConnection _Connection = null;
		InputStream _InputStream = null;
		int _Code = -1;
		String _Result = "";

		try {
			_Connection = getConnection(pUrl, pUrlParamMap, pRequestPropertyMap, pCharset, pTimeOut);
			setRequestBodyParam(_Connection, pBodyParamMap, pCharset);
			_InputStream = _Connection.getInputStream();
			_Code = _Connection.getResponseCode();
			_Result = UtilStream.readStreamAsString(_InputStream, pCharset);
		} finally {
			if (_InputStream != null) {
				_InputStream.close();
			}
			if (_Connection != null) {
				_Connection.disconnect();
			}
			try {
				Log.i("UtilNet", pUrl);
			} catch (NullPointerException e) {
			}
			try {
				Log.i("UtilNet", pUrlParamMap.toString());
			} catch (NullPointerException e) {
			}
			try {
				Log.i("UtilNet", pBodyParamMap.toString());
			} catch (NullPointerException e) {
			}
			try {
				Log.i("UtilNet", pCharset);
			} catch (NullPointerException e) {
			}
			Log.i("UtilNet", _Code + "");
			try {
				Log.i("UtilNet", _Result);
			} catch (NullPointerException e) {
			}
		}

		return _Result;
	}

	public static String encode(Object pObject, String pCharset)
	{
		String _String;
		String _Charset;

		if (pObject == null) {
			_String = "";
		} else {
			_String = pObject.toString();
		}

		if (TextUtils.isEmpty(pCharset)) {
			_Charset = DEFAULT_CHARSET;
		} else {
			_Charset = pCharset;
		}

		String _EncodeString;
		try {
			_EncodeString = URLEncoder.encode(_String, _Charset);
		} catch (UnsupportedEncodingException e) {
			try {
				_EncodeString = URLEncoder.encode(_String, DEFAULT_CHARSET);
			} catch (UnsupportedEncodingException e1) {
				throw new RuntimeException(e1);
			}
		}

		return _EncodeString;
	}

	/**
	 * 判断是否有网络连接
	 * 
	 * @param context
	 * @return
	 */
	public static boolean isConnection()
	{
		try {
			ConnectivityManager _ConnectivityMabager = (ConnectivityManager) ApplicationExtend.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
			NetworkInfo _NetworkInfo = _ConnectivityMabager.getActiveNetworkInfo();
			return _NetworkInfo.isConnected();
		} catch (Exception e) {
			return false;
		}
	}

	public static String getUserAgent()
	{
		StringBuilder _UA = new StringBuilder();
		_UA.append("Mozilla/5.0 (Linux; Android ")
				.append(Build.VERSION.RELEASE)
				.append("; ")
				.append(Locale.getDefault().toString())
				.append("; ")
				.append(Build.MODEL)
				.append(" Build/")
				.append(Build.ID)
				.append(") AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36");
		
		return _UA.toString();
	}

	/**
	 * 在Android ICS中，添加了“HTTP响应缓存”。使用这种缓存，请求可以获得三个好处：
	 * 1.完全缓存的响应从本地存储直接提供。因为响应可以立即得到，所以不用建立网络链接。
	 * 2.有条件缓存的响应一定要由服务器验证是否过期。
	 * 客户端发送一个类似于“给我发送/foo.png，如果从昨天的时候有变化。”的请求，
	 * 服务器要么返回更新后的内容，要么返回“304”未更新代码。
	 * 如果内容没有变化，客户端则不再下载。
	 * 3.没有缓存的响应由服务器提供。这些响应会进行缓存，以便以后复用。
	 * 使用反射，可以在支持这项功能的设备上打开“HTTP响应缓存”。
	 * 调用本方法可以在ICS上打开响应缓存，并不影响以前的版本。
	 */
	private static void enableHttpResponseCache()
	{
		try {
			long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
			File httpCacheDir = new File(ApplicationExtend.getInstance().getCacheDir(), "http");
			Class.forName("android.net.http.HttpResponseCache").getMethod("install", File.class, long.class).invoke(null, httpCacheDir, httpCacheSize);
		} catch (Exception httpResponseCacheNotAvailable) {

		}
	}

	public enum HttpType
	{
		GET("GET"), POST("POST");

		private String	mName;

		private HttpType(String pName)
		{
			mName = pName;
		}

		public String getName()
		{
			return mName;
		}
	}

}
